#include "UART.h"

// UART Receiver buffer
#define DEBUG_RX_BUFFER_SIZE 128
volatile uint8_t debug_rx_buffer[DEBUG_RX_BUFFER_SIZE];
volatile uint16_t debug_rx_wr_index,debug_rx_rd_index,debug_rx_counter;

// This flag is set on USART Receiver buffer overflow
volatile unsigned char debug_rx_buffer_overflow;

USART_TypeDef* COM_USART[COMn] = {COM_DEBUG, COM_GSM,COM_GPS}; 
GPIO_TypeDef* COM_TX_PORT[COMn] = {COM_DEBUG_TX_GPIO_PORT, COM_GSM_TX_GPIO_PORT,COM_GPS_TX_GPIO_PORT};
GPIO_TypeDef* COM_RX_PORT[COMn] = {COM_DEBUG_RX_GPIO_PORT, COM_GSM_RX_GPIO_PORT,COM_GPS_RX_GPIO_PORT};

const uint32_t COM_USART_CLK[COMn] = {COM_DEBUG_CLK, COM_GSM_CLK,COM_GPS_CLK};
const uint32_t COM_TX_PORT_CLK[COMn] = {COM_DEBUG_TX_GPIO_CLK, COM_GSM_TX_GPIO_CLK,COM_GPS_TX_GPIO_CLK};
const uint32_t COM_RX_PORT_CLK[COMn] = {COM_DEBUG_RX_GPIO_CLK, COM_GSM_RX_GPIO_CLK,COM_GPS_RX_GPIO_CLK};
const uint16_t COM_TX_PIN[COMn] = {COM_DEBUG_TX_PIN, COM_GSM_TX_PIN,COM_GPS_TX_PIN};
const uint16_t COM_RX_PIN[COMn] = {COM_DEBUG_RX_PIN, COM_GSM_RX_PIN,COM_GPS_RX_PIN};


/* @brief  Configures COM port. */
void UARTInit()
{
	/* USARTx configured as follow:
        - BaudRate = 115200 baud  
        - Word Length = 8 Bits
        - One Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and CTS signals)
        - Receive and transmit enabled
  	*/

	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  
  /* Enable GPIO clock */
	RCC_APB1PeriphClockCmd(COM_TX_PORT_CLK[COMPC] | COM_RX_PORT_CLK[COMPC] | RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB2PeriphClockCmd(COM_TX_PORT_CLK[COMGSM] | COM_RX_PORT_CLK[COMGSM] | RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB1PeriphClockCmd(COM_TX_PORT_CLK[COMGPS] | COM_RX_PORT_CLK[COMGPS] | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART clock */
	RCC_APB1PeriphClockCmd(COM_USART_CLK[COMPC], ENABLE); 	
	RCC_APB2PeriphClockCmd(COM_USART_CLK[COMGSM], ENABLE);
	RCC_APB1PeriphClockCmd(COM_USART_CLK[COMGPS], ENABLE);
  /* Configure USART Tx as alternate function push-pull */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = COM_TX_PIN[COMPC];
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(COM_TX_PORT[COMPC], &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = COM_TX_PIN[COMGSM];
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(COM_TX_PORT[COMGSM], &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = COM_TX_PIN[COMGPS];
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(COM_TX_PORT[COMGPS], &GPIO_InitStructure);
	
	/* Configure USART Rx as input floating */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = COM_RX_PIN[COMPC];
	GPIO_Init(COM_RX_PORT[COMPC], &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = COM_RX_PIN[COMGSM];
	GPIO_Init(COM_RX_PORT[COMGSM], &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = COM_RX_PIN[COMGPS];
	GPIO_Init(COM_RX_PORT[COMGPS], &GPIO_InitStructure);
	
  	/* USART configuration */
 	USART_Init(COM_USART[COMPC], &USART_InitStructure);
	USART_Init(COM_USART[COMGSM], &USART_InitStructure);
	USART_InitStructure.USART_BaudRate = 9600;
	USART_Init(COM_USART[COMGPS], &USART_InitStructure);	  	

	/* Enable RX Interrupt*/
	USART_ITConfig(COM_USART[COMPC],USART_IT_RXNE, ENABLE);
	USART_ITConfig(COM_USART[COMGSM],USART_IT_RXNE, ENABLE);
	USART_ITConfig(COM_USART[COMGPS],USART_IT_RXNE, ENABLE);

	/* Enable USART */
	USART_Cmd(COM_USART[COMPC], ENABLE);
	USART_Cmd(COM_USART[COMGSM], ENABLE);
	USART_Cmd(COM_USART[COMGPS], ENABLE);
	
	/* Configure the NVIC Preemption Priority Bits */
	NVIC_PriorityGroupConfig(UART_PREEMPTION);
	NVIC_InitStructure.NVIC_IRQChannel = COM_GSM_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = UART_GSM_SUB_PRIORITY;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	NVIC_PriorityGroupConfig(UART_PREEMPTION);
	NVIC_InitStructure.NVIC_IRQChannel = COM_GPS_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = UART_GPS_SUB_PRIORITY;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_PriorityGroupConfig(UART_PREEMPTION);
	NVIC_InitStructure.NVIC_IRQChannel = COM_DEBUG_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = UART_PC_SUB_PRIORITY;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
			
}

void UARTSendByte(USART_TypeDef* USARTx, uint8_t Data){
	USART_SendData(USARTx, (uint8_t)Data);
}

uint8_t UARTReceiveByte(USART_TypeDef* USARTx){
	return (uint8_t)USART_ReceiveData(USARTx);
}

void UART_DEBUG_ISR(void){
	uint8_t data;
	if(USART_GetITStatus(COM_DEBUG, USART_IT_RXNE) != RESET)
	{
		data = USART_ReceiveData(COM_DEBUG);
		debug_rx_buffer[debug_rx_wr_index] = data;
		if (++debug_rx_wr_index == DEBUG_RX_BUFFER_SIZE) debug_rx_wr_index = 0;
		if (++debug_rx_counter == DEBUG_RX_BUFFER_SIZE)
		{
			debug_rx_counter = 0;
			debug_rx_buffer_overflow = 1;
		}
	}
}

void UART_DEBUG_SendByte(unsigned char data)
{
	USART_SendData(COM_DEBUG, data);
	while(USART_GetFlagStatus(COM_DEBUG, USART_FLAG_TXE) == RESET);
}

void UART_DEBUG_SendString(unsigned char *data)
{
	while(*data != NULL){
		UART_DEBUG_SendByte(*data);
		data++;
	}
}

uint8_t UART_DEBUG_ReceivedByte(void)
{
	uint8_t data;
	while (debug_rx_counter == 0);
	data = debug_rx_buffer[debug_rx_rd_index];
	if (++debug_rx_rd_index == DEBUG_RX_BUFFER_SIZE) debug_rx_rd_index=0;
	--debug_rx_counter;
	return data;
}


void UART_DEBUG_ReceivedString(uint8_t *data_buff, uint8_t data_len)
{
	uint8_t i;
	for(i=0;i<data_len;i++){
		data_buff[i] = UART_DEBUG_ReceivedByte();
	}
}

uint8_t UART_DEBUG_RXAvailable(void)
{
	return debug_rx_counter;
}

void UART_DEBUG_RXFlush(void)
{
	while(UART_DEBUG_RXAvailable()){
		UART_DEBUG_ReceivedByte();			//dummy read
	}
}

